#include <stdlib.h>
#include <string.h>
#include <directfb.h>
#include "dtk_types.h"
#include "dtk.h"
#include "dtk_priv.h"
#include "dtk_event.h"

DTKEvent* dtk_event_new(DTKEventType type)
{
    DTKEvent* event;

    event = (DTKEvent*) malloc (sizeof(DTKEvent));
    memset (event, 0, sizeof(DTKEvent));

    return event;
}

void dtk_event_free (DTKEvent* event)
{
    if (NULL != event)
    {
        free (event);
    }
    return;
}

void dtk_event_button_down (DTKActor* stage, DFBWindowEvent* window_event)
{
    dtk_actor_button_down (stage, window_event->x, window_event->y);
    return;
}

void dtk_event_button_up (DTKActor* stage, DFBWindowEvent* window_event)
{
    dtk_actor_button_up (stage, window_event->x, window_event->y);
    return;
}

DBoolean dtk_input_event_proc(DFBInputEvent* input_event)
{
    return DTK_TRUE;
}

DBoolean dtk_window_event_proc(DFBWindowEvent* window_event)
{
    DFBResult ret;
    IDirectFBWindow*    window;
    IDirectFBDisplayLayer* layer;
    DTKActor* stage;

    layer = dtk_get_default_layer();
    ret = layer->GetWindow(layer, window_event->window_id, &window);
    if (ret != DFB_OK)
    {
        return DTK_FALSE;
    }

    window->GetProperty (window, "stage", (void**) &stage);

    switch (window_event->type)
    {
        case DWET_POSITION:
            printf ("DWET_POSITION\n");
            break;
        case DWET_SIZE:
            printf ("DWET_SIZE\n");
            break;
        case DWET_CLOSE:
            printf ("DWET_CLOSE\n");
            break;
        case DWET_DESTROYED:
            printf ("DWET_DESTROYED\n");
            break;
        case DWET_GOTFOCUS:
            printf ("DWET_GOTFOCUS\n");
            break;
        case DWET_LOSTFOCUS:
            printf ("DWET_LOSTFOCUS\n");
            break;
        case DWET_KEYDOWN:
            printf ("DWET_KEYDOWN\n");
            break;
        case DWET_KEYUP:
            printf ("DWET_KEYUP\n");
            break;
        case DWET_BUTTONDOWN:
            dtk_event_button_down(stage, window_event);
            //printf ("DWET_BUTTONDOWN\n");
            break;
        case DWET_BUTTONUP:
            dtk_event_button_up(stage, window_event);
            //printf ("DWET_BUTTONUP\n");
            break;
        case DWET_MOTION:
            //printf ("DWET_MOTION\n");
            break;
        case DWET_ENTER:
            printf ("DWET_ENTER\n");
            break;
        case DWET_WHEEL:
            printf ("DWET_WHEEL\n");
            break;
        case DWET_NONE:
            printf ("DWET_NONE\n");
        default:
            break;
    }
    return DTK_TRUE;
}

static DBoolean dtk_user_event_proc(DFBUserEvent* user_event)
{
    switch (user_event->type)
    {
        case DTK_EVENT_PAINT:
        {            
        }    
            break;
        default:
            break;
    }
    return DTK_TRUE;
}

DBoolean dtk_event_loop(DInt fps)
{
    DFBResult ret;
    IDirectFBEventBuffer* ev;
    DFBEvent event;
    long long last_update_time = 0;
    long long now;
    long long minimum_update_freq = 200;
    DTKActor* stage;

    stage = dtk_get_default_stage();

    if (fps > 30)
    {
        fps = 30;
    }

    if (fps < 10)
    {
        fps = 10;
    }

    minimum_update_freq = 1000 / fps;

    ev = dtk_get_default_eventbuffer();
    dtk_layout_relayout (dtk_actor_get_layout(stage));
    
    while(DTK_TRUE)
    {
        if (DFB_BUFFEREMPTY != ev->HasEvent(ev))
        {
            ev->GetEvent (ev, &event);

            switch (event.clazz)
            {
                case DFEC_INPUT:
                    printf ("DFEC_INPUT\n");
                    break;
                case DFEC_WINDOW:
                    dtk_window_event_proc(&event.window);
                    break;
                case DFEC_USER:
                    dtk_user_event_proc (&event.user);                    
                    break;
                case DFEC_UNIVERSAL:
                    printf ("DFEC_UNIVERSAL\n");                        
                    break;
                case DFEC_VIDEOPROVIDER:
                    printf ("DFEC_VIDEOPROVIDER\n");                        
                    break;
                case DFEC_NONE:
                default:
                    printf ("DFEC_NONE\n");                        
                    break;
            }            
        }


        now = direct_clock_get_millis();

        if (now - last_update_time >= minimum_update_freq)
        {
            DTKMasterClock* clock;

            clock = dtk_get_default_master_clock();
            dtk_mc_active (clock);
            dtk_layout_relayout (dtk_actor_get_layout(stage));
            dtk_stage_draw(stage);
            last_update_time = now;
        }
        else
        {
            ev->WaitForEventWithTimeout(ev, 0,
                minimum_update_freq - (now - last_update_time));
        }
        
    }
}

void dtk_event_post(DTKEvent* event)
{
    IDirectFBEventBuffer* event_buffer;
    DFBUserEvent   dfb_event;

    event_buffer = dtk_get_default_eventbuffer();
    dfb_event.clazz = DFEC_USER;
    dfb_event.type = DTK_EVENT_PAINT;
    dfb_event.data = event;
    event_buffer->PostEvent(event_buffer, &dfb_event);
    event_buffer->WakeUp(event_buffer);
    return;
}

void dtk_event_wakeup()
{
    IDirectFBEventBuffer* event_buffer;

    event_buffer = dtk_get_default_eventbuffer();
    event_buffer->WakeUp(event_buffer);
    return;
}

